﻿using EmgrMvc.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Quartz;
using Quartz.Impl;
using Microsoft.EntityFrameworkCore;
using System.Collections;

namespace EmgrMvc.BLL
{
    public class EsysBLL
    {
        MyContext db;
        MqttTool mqttTool;

        public EsysBLL(MyContext db)
        {
            this.db = db;
            mqttTool = MqttTool.getSingleton(); // new MqttTool();
        }

        public void InitData()
        {
            db.MqttControllers.Add(new MqttController { ID = "home202", Name = "家里的", Path= "home/202", Description = "家里面用于测试的" });
            db.MqttControllers.Add(new MqttController { ID = "u206", Name = "u206", Path = "ulab/u206", Description = "U206实验室" });

            db.Groups.AddRange(new DeviceGroup[] { 
                new DeviceGroup{ Name="S101", Description= "S101"},
                new DeviceGroup{ Name="S201", Description= "S202"}
            });

            db.Types.AddRange(new DeviceType[]
            {
                new DeviceType{ Id="gree", Name="Gree", Catalog="IR", DataFileOn="gree_on.txt", DataFileOff = "gree_off.txt", Descrition = "格力空调"},
                new DeviceType{ Id="midea", Name="Midea", Catalog="IR", DataFileOn="midea_on.txt", DataFileOff = "midea_off.txt", Descrition = "美的空调"},
                new DeviceType{ Id="switch", Name="Relay", Catalog="Relay", DataFileOn="", DataFileOff = "", Descrition = "继电器"},
                new DeviceType{ Id="wol", Name="WOL", Catalog="WOL", Descrition="WOL"}
            });

            db.Devices.AddRange(new Device[]
            {
                new Device { Name = "家里的格力空调", Type="gree", ControllerNode = "home/202", Topic="/ir/1", Data="", Status = "OFF"},
                new Device { Name = "家里的电脑", Type="wol", ControllerNode = "home/202", Topic="/wol", Data="F0:2F:74:DD:98:96", Status = "OFF"},
                new Device { Name = "U206空调A", Type="midea", ControllerNode = "ulab/u206", Topic="/ir/1", Data="", Status = "OFF", Description = "前面的空调"},
                new Device { Name = "U206空调B", Type="midea", ControllerNode = "ulab/u206", Topic="/ir/2", Data="", Status = "OFF", Description = "后面的空调"}
            });

            db.GroupMembers.AddRange(new GroupMember[]
            {
                new GroupMember{ GroupId=1, DeviceId=1},
                new GroupMember{ GroupId=1, DeviceId=2},
                new GroupMember{ GroupId=2, DeviceId=1}
            }) ;

            db.jobDatas.AddRange(new JobData[]
            {
                new JobData{ Name="Device at Home", groupId = 1, Action = "ON", Description = ""},
                new JobData{ Name="Device at Office", groupId = 2, Action = "ON", Description = ""}
            }
            );

            db.Triggers.AddRange(new Trigger[]
            {
                new Trigger { Name="周一1-2节上课前", WeekDay = 1, Hour = 8, Minute = 50, Second = 0, Description = ""},
                new Trigger { Name="周一3-4节下课后", WeekDay = 1, Hour = 12, Minute = 10, Second = 0, Description = ""},
            });

            db.scheduleJobs.Add(new ScheduleJob { Name = "test", triggerId = 1, jobDataId = 1, active = true });

            db.OntimeJobs.AddRange(new OntimeJob[]
            {
                new OntimeJob { Name="test1", Weekday=1, OddEvenWeek="BOTH", Hour=8, Minute=0, Second=0, DeviceOrGroup="DEVICE", DeviceOrGroupId=1, Action="ON", Active = true},
                new OntimeJob { Name="test2", Weekday=1, OddEvenWeek="BOTH", Hour=8, Minute=30, Second=0, DeviceOrGroup="GROUP", DeviceOrGroupId=1, Action="OFF", Active = true}
            });

            db.SaveChanges();
        }

        public void RemoveGroupDevice(int id, int deviceWillAdd)
        {
            var devicesWillBeRemove = db.GroupMembers.Where(x => x.GroupId == id && x.DeviceId == deviceWillAdd).ToList();
            foreach(var dev in devicesWillBeRemove)
            {
                db.GroupMembers.Remove(dev);
            }
            db.SaveChanges();
        }

        public void AddGroupDevice(int id, int deviceWillAdd)
        {
            db.GroupMembers.Add(new GroupMember { GroupId = id, DeviceId = deviceWillAdd });
            db.SaveChanges();
        }

        public List<Device> getDevices()
        {
            return db.Devices.ToList();
        }

        public string Test()
        {
            return "Hello";
        }

        public List<Device> getDevicesByGroup(int groupId)
        {
            var q = from d in db.Devices join gm in db.GroupMembers on d.Id equals gm.DeviceId
                    where gm.GroupId == groupId select d;
            return q.ToList();
        }

        public void PowerOnDevice(int deviceId)
        {
            Device device = db.Devices.Find(deviceId);
            DeviceType deviceType = db.Types.Find(device.Type);

            switch(deviceType.Catalog)
            {
                case "IR":
                    mqttTool.ACControl("action/on/" + device.ControllerNode + device.Topic, "Data/" + deviceType.DataFileOn);
                    break;
                case "WOL":
                    mqttTool.WakeupPC("action/on/" + device.ControllerNode + "/wol", device.Data);
                    break;
                case "SWITCH":
                    mqttTool.SwitchOn("action/on/" + device.ControllerNode + device.Topic);
                    break;
                default:
                    throw new ArgumentException();
            }
        }

        public void PowerOffDevice(int deviceId)
        {
            Device device = db.Devices.Find(deviceId);
            DeviceType deviceType = db.Types.Find(device.Type);

            switch (deviceType.Catalog)
            {
                case "IR":
                    mqttTool.ACControl("action/off/" + device.ControllerNode + device.Topic, "Data/" + deviceType.DataFileOff);
                    break;
                case "WOL":
                    mqttTool.WakeupPC("action/off/" + device.ControllerNode + "/wol", device.Data);
                    break;
                case "SWITCH":
                    mqttTool.SwitchOff("action/off/" + device.ControllerNode + device.Topic);
                    break;
                default:
                    throw new ArgumentException();
            }
        }

        public void PowerOffByGroup(int groupId)
        {
            //MqttTool mqttTool = new MqttTool(db);

            var q = from d in db.Devices
                    join gm in db.GroupMembers on d.Id equals gm.DeviceId
                    where gm.GroupId == groupId
                    select d;
            List<Device> devices = q.ToList();

            foreach (Device d in devices)
            {
                PowerOffDevice(d.Id);
            }
        }

        public void PowerOnByGroup(int groupId)
        {
            //MqttTool mqttTool = new MqttTool(db);

            var q = from d in db.Devices
                    join gm in db.GroupMembers on d.Id equals gm.DeviceId
                    where gm.GroupId == groupId
                    select d;
            List<Device> devices = q.ToList();

            foreach(Device d in devices)
            {
                PowerOnDevice(d.Id);
            }
        }

        public void UpdateDeviceStatus(string topic, string status)
        {
            //Device device = db.Devices.Find(deviceId);
            Device device = db.Devices.Single(d => d.ControllerNode + d.Topic == topic);
            device.Status = status;
            device.Latest = DateTime.Now;
            db.SaveChanges();
        }

        public void InitOntimeJob(IScheduler scheduler)
        {
            //var jobDetail = JobBuilder.Create<SayHelloJob>()
            //        .WithIdentity("id1", "group1")
            //        .SetJobData(new JobDataMap() {
            //        new KeyValuePair<string, object>("UserName", "Tom")
            //    }).Build();
            //var trigger = TriggerBuilder.Create()
            //                            //.WithCronSchedule("0 3 6 * * ?")
            //                            //.WithSimpleSchedule(m => m.WithRepeatCount(3).WithIntervalInMinutes(1))
            //                            .StartAt(DateTime.Now + TimeSpan.FromSeconds(30))
            //                            .Build();

            ////添加调度
            //scheduler.ScheduleJob(jobDetail, trigger);
            scheduler.Clear().Wait();
            foreach(OntimeJob job in db.OntimeJobs.AsNoTracking().Where(x => x.Active))
            {
                Console.WriteLine(JsonSerializer.Serialize(job));
                var jobDetail = JobBuilder.Create<AppJob>()
                       // .WithIdentity("id1", "group1")
                        .SetJobData(new JobDataMap() {
                            new KeyValuePair<string, object>("Db", db),
                            new KeyValuePair<string, object>("IsGroup", job.DeviceOrGroup == "GROUP"),
                            new KeyValuePair<string, object>("GroupId", job.DeviceOrGroupId),
                            new KeyValuePair<string, object>("IsEven", job.OddEvenWeek == "EVEN"),
                            new KeyValuePair<string, object>("Action", job.Action),
                    }).Build();

                string cron = string.Format("{0} {1} {2} ? * {3}", job.Second, job.Minute, job.Hour, job.Weekday);
                Console.WriteLine(cron);

                var trigger = TriggerBuilder.Create()
                    .WithCronSchedule(cron)
                    .Build();

                scheduler.ScheduleJob(jobDetail, trigger).Wait();
            }
        }
    }
}
